<?php
//require 'common.php';

class SpeedLimit{
  var $DateCheck;
  var $FromCheck;
  var $ToCheck;
  var $Speed;
  var $Day;
  var $FromTimeH;
  var $FromTimeM;
  var $FromTimeS;
  var $ToTimeH;
  var $ToTimeM;
  var $ToTimeS;
  var $DateY;
  var $DateM;
  var $DateD;

  public function GetRequiredBufferLen(){
    return 4 + //Speed
           4 + //date
           6 + //2 * time
           1;  //Weekday
  }

  public function FillBuffer(&$data, &$p){
    $data[$p++] = chr( $this->Speed >> 24);
    $data[$p++] = chr(($this->Speed >> 16) % 256);
    $data[$p++] = chr(($this->Speed >>  8) % 256);
    $data[$p++] = chr( $this->Speed %  256);
    
    if($this->DateCheck){
      $data[$p++] = $this->DateY >> 8;
      $data[$p++] = $this->DateY %  256;
      $data[$p++] = $this->DateM;
      $data[$p++] = $this->DateD;
    }else{
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
    }

    if($this->FromCheck){
      $data[$p++] = chr($this->FromTimeH);
      $data[$p++] = chr($this->FromTimeM);
      $data[$p++] = chr($this->FromTimeS);
    }else{
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
    }

    if($this->ToCheck){
      $data[$p++] = chr($this->ToTimeH);
      $data[$p++] = chr($this->ToTimeM);
      $data[$p++] = chr($this->ToTimeS);
    }else{
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
      $data[$p++] = chr(0);
    }

    $data[$p++] = $this->Day;
  }

  public function Init(&$data){
    $pData = &$data;
    if(strlen($pData) < 4+4+6+1)
      return false;
    
    $this->Speed  = ord($pData[0]) << 24; $pData = substr($pData, 1);
    $this->Speed |= ord($pData[0]) << 16; $pData = substr($pData, 1);
    $this->Speed |= ord($pData[0]) << 8;  $pData = substr($pData, 1);
    $this->Speed |= ord($pData[0]);       $pData = substr($pData, 1);
    if($this->Speed > 1048576)
      $this->Speed = 1048576;

    if(ord($pData[0])==0 && ord($pData[1])==0 && ord($pData[2])==0 && ord($pData[3])==0){
      $pData = substr($pData, 4);
      $this->DateCheck = false;
    }else{
      $this->DateCheck = true;
      $this->DateY  = ord($pData[0]) << 8; $pData = substr($pData, 1);
      $this->DateY |= ord($pData[0]);      $pData = substr($pData, 1);
      ParserByte($pData, $this->FromTimeM);
      ParserByte($pData, $this->FromTimeD);
      if($this->DateY<1900 || $this->DateY>3000 || $this->DateM<1 || $this->DateM>12 ||
	 $this->DateD<1    || $this->DateD>31)
	return false;     
    }

    if(ord($pData[0])==0 && ord($pData[1])==0 && ord($pData[2])==0){
      $pData = substr($pData, 3);
      $this->FromCheck = false;
    }else{
      $this->FromCheck = true;
      ParserByte($pData, $this->FromTimeH);
      ParserByte($pData, $this->FromTimeM);
      ParserByte($pData, $this->FromTimeS);
    }

    if(ord($pData[0])==0 && ord($pData[1])==0 && ord($pData[2])==0){
      $pData = substr($pData, 3);
      $this->ToCheck = false;
    }else{
      $this->ToCheck = true;
      ParserByte($pData, $this->ToTimeH);
      ParserByte($pData, $this->ToTimeM);
      ParserByte($pData, $this->ToTimeS);
    }

    ParserByte($pData, $this->Day);
    return true;
  }
}

class Group{
  var $GroupName;
  var $IPLimit;
  var $UserLimit;
  var $BypassUserLimit;  
  var $Enabled;
  var $DisallowIPs = array();
  var $AllowedIPs = array();
  var $Permissions = array();
  var $SpeedLimitType = array("", "");
  var $SpeedLimit = array("", "");
  var $BypassServerSpeedLimit = array("", "");
  var $SpeedLimits = array(array(), array());
  var $Comment;
  var $ForceSsl;
  //  var $NumDisallowedIPs;

  public function GetRequiredBufferLen(){
    $len = 9;
    $len += GetRequiredStringBufferLen($this->GroupName);
    
    $len += 4;
    foreach($this->DisallowIPs as $value)
      $len += GetRequiredStringBufferLen($value);
    foreach($this->AllowedIPs as $value)
      $len += GetRequiredStringBufferLen($value);

    $len += 2;
    foreach($this->Permissions as $value){
      $len += 2;
      
      $len += GetRequiredStringBufferLen($value->Dir);

      $len += 2;
      foreach($value->Aliases as $value2){
	$len += GetRequiredStringBufferLen($value2);
      }
    }

    //Speed Limits.
    $len += 6;  //Basic Limits.
    $len += 4;  //Number of rules.
    for($i = 0; $i < 2;$i++){
      foreach($this->SpeedLimits[$i] as $value){
	$len += $value->GetRequiredBufferLen();
      }
    }

    $len += GetRequiredStringBufferLen($this->Comment);
    
    $len++; //forceSsl;

    printf("GroupName=%s RequiredBufferLen=%d\r\n", $this->GroupName, $len);
    return $len;
  }

  public function FillBuffer(&$data, &$p){
    FillString($data, $p, $this->GroupName);
    FillInt($data, $p, $this->IPLimit);
    FillInt($data, $p, $this->UserLimit);
    
    $options  = $this->BypassUserLimit & 3;
    $options |= ($this->Enabled & 3) << 2;
    $data[$p++] = chr($options & 0xFF);

    $data[$p++] = chr(count($this->DisallowIPs) >> 8);
    $data[$p++] = chr(count($this->DisallowIPs) &  0xFF);
    foreach($this->DisallowIPs as $value)
      FillString($data, $p, $value);

    $data[$p++] = chr(count($this->AllowedIPs) >> 8);
    $data[$p++] = chr(count($this->AllowedIPs) &  0xFF);
    foreach($this->AllowedIPs as $value)
      FillString($data, $p, $value);

    $data[$p++] = chr(count($this->Permissions) >> 8);
    $data[$p++] = chr(count($this->Permissions) &  0xFF);
    foreach($this->Permissions as $value){
      FillString($data, $p, $value->Dir);

      $data[$p++] = chr(count($value->Aliases) >> 8);
      $data[$p++] = chr(count($value->Aliases) &  0xFF);
      foreach($value->Aliases as $value2){
	FillString($data, $p, $value2);
      }

      $rights  = 0;
      $rights |= $value->boDirCreate  ? 0x0001:0;
      $rights |= $value->boDirDelete  ? 0x0002:0;
      $rights |= $value->boDirList    ? 0x0004:0;
      $rights |= $value->boDirSubDirs ? 0x0008:0;
      $rights |= $value->boFileAppend ? 0x0010:0;
      $rights |= $value->boFileDelete ? 0x0020:0;
      $rights |= $value->boFileRead   ? 0x0040:0;
      $rights |= $value->boFileWrite  ? 0x0080:0;
      $rights |= $value->boIsHome     ? 0x0100:0;
      $rights |= $value->boAutoCreate ? 0x0200:0;
      $data[$p++] = chr($rights >> 8);
      $data[$p++] = chr($rights &  0xFF);
    }//end if

    for($i = 0; $i < 2; $i++){
      $data[$p++] = chr($this->SpeedLimitType[$i] & 3 + ($this->BypassServerSpeedLimit[$i] & 3) << 2);
      $data[$p++] = chr($this->SpeedLimit[$i] >> 8);
      $data[$p++] = chr($this->SpeedLimit[$i] &  0xFF);

      $data[$p++] = chr(count($this->SpeedLimits[$i]) >> 8);
      $data[$p++] = chr(count($this->SpeedLimits[$i]) &  0xFF);
      foreach($this->SpeedLimits[$i] as $value){
	$value->FillBuffer($data, $p);
      }
    }

    FillString($data, $p, $this->Comment);

    $data[$p++] = chr($this->ForceSsl);
  }

  public function Init(&$data){
    $pData = &$data;
    if(!ParserString($pData, $this->GroupName))
      return false;   

    if(strlen($pData) < 11)
      return false;

    ParserInt($pData, $this->IPLimit);
    ParserInt($pData, $this->UserLimit);
    ParserByte($pData,$nOptions);
    $this->BypassUserLimit = $nOptions & 0x03;
    $this->Enabled = ($nOptions >> 2) & 0x03;
    ParserWord2($pData, $NumDisallowedIPs);
    while($NumDisallowedIPs--){
      if(!ParserString($pData, $Ip))
	return false;
      array_push($this->DisallowIPs, $Ip);
    }

    if(strlen($pData) < 2)
      return false;
    ParserWord2($pData, $numAllowedIPs);
    while($numAllowedIPs--){
      if(!ParserString($pData, $ip))
	return false;
      array_push($this->AllowedIPs, $ip);
    }
    
    if(strlen($pData) < 2)
      return false;
    ParserWord2($pData, $dircount);
    $boGotHome = false;
    for($j = 0; $j < $dircount; $j++){
      $dirObj = new stdClass();
      $dirObj->Aliases = Array();
      $dirObj->Dir = "";
      if(!ParserString($pData, $str))
	return false;
      $dirObj->Dir = $str;

      ParserWord2($pData, $aliascount);
      for($i = 0; $i < $aliascount; $i++){
	if(!ParserString($pData, $alias))
	  return false;
	array_push($dirObj->Aliases, $alias);
      }

      if(strlen($pData) < 2)
	return false;

      ParserWord2($pData, $rights);
      $dirObj->boDirCreate  = $rights & 0x0001 ? 1:0;
      $dirObj->boDirDelete  = $rights & 0x0002 ? 1:0;
      $dirObj->boDirList    = $rights & 0x0004 ? 1:0;
      $dirObj->boDirSubDirs = $rights & 0x0008 ? 1:0;
      $dirObj->boFileAppend = $rights & 0x0010 ? 1:0;
      $dirObj->boFileDelete = $rights & 0x0020 ? 1:0;
      $dirObj->boFileRead   = $rights & 0x0040 ? 1:0;
      $dirObj->boFileWrite  = $rights & 0x0080 ? 1:0;
      $dirObj->boIsHome     = $rights & 0x0100 ? 1:0;
      $dirObj->boAutoCreate = $rights & 0x0200 ? 1:0;

      if($dirObj->boIsHome)
	if(!$boGotHome)
	  $boGotHome = true;
        else
	  $dirObj->boIsHome = false;
      
      array_push($this->Permissions, $dirObj);
    }//end for

    for($i = 0; $i < 2; $i++){
      if(strlen($pData) < 5)
	return false;

      $this->SpeedLimitType[$i] = ord($pData[0]) & 3;
      $this->BypassServerSpeedLimit[$i] = (ord($pData[0]) >> 2) & 3; $pData = substr($pData, 1);
      
      $this->SpeedLimit[$i]  = (ord($pData[0]) << 8); $pData = substr($pData, 1);
      $this->SpeedLimit[$i] |= ord($pData[0]); $pData = substr($pData, 1);

      if(!$this->SpeedLimit[$i])
	$this->SpeedLimit[$i] = 10;

      ParserWord2($pData, $num);
      while($num--){
	$speedLimitObj = new SpeedLimit();
	if($speedLimitObj->Init($pData))
	  array_push($this->SpeedLimits[$i], $speedLimitObj);
	else
	  return false;
	if(strlen($pData)<=0)
	  return false;
      }      				      
    }
    if(!ParserString($pData, $this->Comment))
      return false;

    if(strlen($pData) > 0)
      ParserByte($pData, $this->ForceSsl);

    printf("init\r\n");
    return true;
  }

  public function CreateNew($userName, $dir){
    $this->GroupName = "";
    $this->IPLimit = 0;
    $this->UserLimit = 0;
    $this->BypassUserLimit = 0;
    $this->Enabled = 1;
    $dirObj = new stdClass();
    $dirObj->Aliases = Array();
    $dirObj->Dir = $dir;   
    $dirObj->boDirCreate  = 1;
    $dirObj->boDirDelete  = 1;
    $dirObj->boDirList    = 1;
    $dirObj->boDirSubDirs = 1;
    $dirObj->boFileAppend = 1;
    $dirObj->boFileDelete = 1;
    $dirObj->boFileRead   = 1;
    $dirObj->boFileWrite  = 1;
    $dirObj->boIsHome     = 1;
    $dirObj->boAutoCreate = 0;
    array_push($this->Permissions, $dirObj); 
  }
}

class User extends Group{
  var $UserName;
  var $Password;
  
  public function GetRequiredBufferLen(){
    $len  = parent::GetRequiredBufferLen();
    $len += GetRequiredStringBufferLen($this->UserName);
    $len += GetRequiredStringBufferLen($this->Password);
    printf("UserName=%s RequiredBufferLen=%d\r\n", $this->UserName, $len);
    return $len;
  }

  public function FillBuffer(&$data, &$p){
    parent::FillBuffer($data, $p);

    FillString($data, $p, $this->UserName);
    FillString($data, $p, $this->Password);
  }

  public function Init(&$data){
    $pData = &$data;
    if(!parent::Init($pData))
      return false;

    ParserString($pData, $this->UserName);
    ParserString($pData, $this->Password);
    printf("User.UserName=%s User.Password=%s len=%d\r\n", $this->UserName, $this->Password, strlen($pData));
    return true;
  }

  public function CreateNew($userName, $dir){
    $this->UserName = $userName;
    $this->Password = "";
    parent::CreateNew($userName, $dir);
  }
}

class UserAdmin{
  var $GroupList = array();
  var $UserList  = array();

  public function Init(&$data){
    $pData = $data;

    if(strlen($pData) < 2)
      return false;
    ParserWord($pData, $num);
    printf("useradmin.init groupnum=%d\r\n", $num);
    for($i = 0; $i < $num; $i++){
      $groupObj = new Group();
      if(!$groupObj->Init($pData)){
	Error("Group.ini error!\r\n");
	return false;
      }
      array_push($this->GroupList, $groupObj);
      printf("group%d name=%s\r\n", $i, $groupObj->GroupName);
      if(strlen($pData)<=0)
	break;      
    }

    if(strlen($pData) < 2)
      return false;
    ParserWord($pData, $num);
    printf("useradmin.init usernum=%d\r\n", $num);
    for($i = 0; $i < $num; $i++){
      $userObj = new User();
      if(!$userObj->Init($pData)){
	printf("User.init error!\r\n");
	print_r($userObj);
	return false;
      }
      array_push($this->UserList, $userObj);
      if(strlen($pData) <= 0)
	break;
    }
    printf("useradmin.init\r\n");
    print_r($this->UserList);
    if(GetCmd() == 'dump'){      
      Terminate();
    }
    return true;
  }

  public function FillBuffer(&$setingData){
    $len = 4;

    foreach($this->GroupList as $groupObj)
      $len += $groupObj->GetRequiredBufferLen();
    
    foreach($this->UserList as $userObj)
      $len += $userObj->GetRequiredBufferLen();

    $p = 0;
    $data = array();
    for($i = 0; $i < $len; $i++)
      array_push($data, "\0");

    $data[0] = 'a';
    $data[$p++] = chr(count($this->GroupList) / 256);
    $data[$p++] = chr(count($this->GroupList) % 256);
    foreach($this->GroupList as $groupObj){
      $groupObj->FillBuffer($data, $p);
    }

    if(GetCmd() == "chgdir"){
      $boFound = false;
      $boFoundUser = false;
      foreach($this->UserList as $userObj){
	if($userObj->UserName == $GLOBALS['gParams']['user']){	
	  $boFoundUser = true;
	  foreach($userObj->Permissions as $dirObj){
	    if($dirObj->Dir == $GLOBALS['gParams']['dir']){
	      $boFound = true;
	      break;
	    }
	  }
	  if(!$boFound && count($userObj->Permissions)>0){
	    $userObj->Permissions[0]->Dir = $GLOBALS['gParams']['dir'];
	    print_r($this);
	  }else{
	    printf("not found user=%s dir=%s\r\n", $GLOBALS['gParams']['user'], $GLOBALS['gParams']['dir']);
	  }
	}
      }//end for
      if(!$boFoundUser){
	$newUser = new User();
	$newUser->CreateNew($GLOBALS['gParams']['user'], $GLOBALS['gParams']['dir']);
	array_push($this->UserList, $newUser);
	printf("%s not found, created the user.", $GLOBALS['gParams']['user']);
      }
    }

    $data[$p++] = chr(count($this->UserList) / 256);
    $data[$p++] = chr(count($this->UserList) % 256);
    foreach($this->UserList as $userObj){
      $userObj->FillBuffer($data, $p);
    }

        
    
    $setingData = "";
    for($i = 0; $i < count($data); $i++){
      $setingData .= $data[$i];
      $data[$i] = bin2hex(($data[$i]));
    }
    print_r($this);
    //print($setingData);
    //$userA = new UserAdmin();
    //$userA->Init($setingData);
  }
}

?>